//---------------------------------------------------------------------
// File: OrchestrationConductorStep.cs
// 
// Summary: 
//
//---------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, WHETHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//---------------------------------------------------------------------

namespace Microsoft.Services.BizTalkApplicationFramework.BizUnit
{
	using System;
	using System.Management;
	using System.Xml;
	using Microsoft.Services.BizTalkApplicationFramework.BizUnit;

	/// <summary>
	/// The OrchestrationConductorStep may be used to stop/start an orchestration.
	/// </summary>
	/// 
	/// <remarks>
	/// The following shows an example of the Xml representation of this test step.
	/// 
	/// <code escaped="true">
    /// <TestStep assemblyPath="" typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.OrchestrationConductorStep, Microsoft.Services.BizTalkApplicationFramework.BizUnit.BizTalkSteps">
	///		<DelayForCompletion>5</DelayForCompletion> <!-- Optional, seconds to delay for this step to complete -->
	///		<AssemblyName>BizUnitTest.Process</AssemblyName>
	///		<OrchestrationName>BizUnitTest.Process.SubmitToLedger</OrchestrationName>
	///		<Action>Start</Action>
	/// </TestStep>
	/// </code>
	///	<list type="table">
	///		<listheader>
	///			<term>Tag</term>
	///			<description>Description</description>
	///		</listheader>
	///		<item>
	///			<term>DelayForCompletion</term>
	///			<description>The delay before executing the step <para>(optional)</para></description>
	///		</item>
	///		<item>
	///			<term>AssemblyName</term>
	///			<description>The name of the assembly containing the orchestration, e.g. BizUnitTest.Process</description>
	///		</item>
	///		<item>
	///			<term>OrchestrationName</term>
	///			<description>The name of the orchestration to start/stop</description>
	///		</item>
	///		<item>
	///			<term>Action</term>
	///			<description>Start|Stop</description>
	///		</item>
	///	</list>
	///	</remarks>	
	 
	public class OrchestrationConductorStep : ITestStep
	{
		internal enum OrchestrationAction 
		{
			Start,
			Stop,
		}

		/// <summary>
		/// ITestStep.Execute() implementation
		/// </summary>
		/// <param name='testConfig'>The Xml fragment containing the configuration for this test step</param>
		/// <param name='context'>The context for the test, this holds state that is passed beteen tests</param>
		public void Execute(XmlNode testConfig, Context context)
		{
			string assemblyName = context.ReadConfigAsString(testConfig, "AssemblyName");
			string orchestrationName = context.ReadConfigAsString(testConfig, "OrchestrationName");

			OrchestrationAction action = (OrchestrationAction)Enum.Parse( typeof(OrchestrationAction), context.ReadConfigAsString(testConfig, "Action"), true );

			try 
			{
				if ( action == OrchestrationAction.Start )
				{
					Start( assemblyName, orchestrationName, context );
				}
				else
				{
					Stop( assemblyName, orchestrationName, context );
				}

				// Delay if necessary to allow the orchestration to start/stop
				int delayForCompletion = context.ReadConfigAsInt32(testConfig, "DelayForCompletion", true);
				if (delayForCompletion > 0)
				{
					context.LogInfo("Waiting for {0} seconds before recommencing testing.", delayForCompletion);
					System.Threading.Thread.Sleep(delayForCompletion*1000);
				}
			} 
			catch ( System.Runtime.InteropServices.COMException e )
			{
				context.LogException( e );
				throw;
			}
		}

		private static void Start( string assemblyName, string orchestrationName, Context context )
		{
			bool started = false;
			string WMIQuery = 
				String.Format("Select * from MSBTS_Orchestration where Name=\"{0}\" and AssemblyName=\"{1}\"", orchestrationName, assemblyName);

			EnumerationOptions enumOptions = new EnumerationOptions();
			enumOptions.ReturnImmediately = false;

			ManagementObjectSearcher OrchestrationSearcher = new ManagementObjectSearcher("root\\MicrosoftBizTalkServer",	WMIQuery, enumOptions);							

			foreach( ManagementObject OrchestrationInstance in OrchestrationSearcher.Get())
			{
				context.LogInfo("Starting Orchestration: {0}", orchestrationName);
				OrchestrationInstance.InvokeMethod("Start", new object[] {2,2});

				context.LogInfo("Orchestration: {0} was successfully started", orchestrationName);
				started = true;
			}				
			
			if ( !started )
			{
				throw new ApplicationException(string.Format("Failed to start the orchestration: \"{0}\"", orchestrationName));
			}							
		}

		private static void Stop( string assemblyName, string orchestrationName, Context context )
		{
			bool stopped = false;
			string WMIQuery = 
				String.Format( "Select * from MSBTS_Orchestration where Name=\"{0}\" and AssemblyName=\"{1}\"", orchestrationName, assemblyName);

			EnumerationOptions enumOptions = new EnumerationOptions();
			enumOptions.ReturnImmediately = false;

			ManagementObjectSearcher OrchestrationSearcher = new ManagementObjectSearcher("root\\MicrosoftBizTalkServer",	WMIQuery, enumOptions);							

			foreach( ManagementObject OrchestrationInstance in OrchestrationSearcher.Get())
			{
				OrchestrationInstance.InvokeMethod("Stop", new object[] {2,2});

				context.LogInfo("Orchestration: {0} was successfully stopped", orchestrationName);
				stopped = true;
			}	
			
			if ( !stopped )
			{
				throw new ApplicationException(string.Format("Failed to stop the orchestration: \"{0}\"", orchestrationName));
			}																									
		}
	}
}